#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <sys/time.h>

#include "src/CryptoPrimitive.hh"
#include "chunking.hh"
#include "encoding.hh"
#include "downloading.hh"
#define FILE_HEAD (-9)
#define BLOCKCP (-8)
#define BLOCKCP_END (-7)

using namespace std;


Chunker* chunkObj;
Encoder* encoderObj;
Decoder* decoderObj;
Uploader* uploaderObj;
Downloader* downloaderObj;
void timerStart(double *t){
    struct timeval tv;
    gettimeofday(&tv, NULL);
    *t = (double)tv.tv_sec+(double)tv.tv_usec*1e-6;
}

double timerSplit(const double *t){
    struct timeval tv;
    double cur_t;
    gettimeofday(&tv, NULL);
    cur_t = (double)tv.tv_sec + (double)tv.tv_usec*1e-6;
    return (cur_t - *t);
}


int main(int argc, char *argv[]){

  int n=4;
  int m=2;
  int r=n-m-1;
  unsigned char *buffer;
  unsigned char* blockbuffer;
  char* opt=argv[2];
  int size;
  int userId=atoi(argv[3]);
  int buffersize;
  int left,chunklength;

  //open the file
  FILE * fin = fopen(argv[1],"r");
  fseek(fin,0,SEEK_END);
  size=ftell(fin);
  fseek(fin,0,SEEK_SET);
  buffersize=sizeof(unsigned char)*size;
  
   /* full file name process */
    int namesize = 0;
    while(argv[1][namesize] != '\0'){
        namesize++;
    }
    namesize++;

  //read the file
  buffer=(unsigned char*)malloc(buffersize);
  int l=fread(buffer,1,buffersize,fin);
  if(l!=buffersize)
    printf("read error\n");


  if(!CryptoPrimitive::opensslLockSetup()) {
      printf("fail to set up OpenSSL locks\n");
        return 0;
  }

  //upload the file
  if(strncmp(opt,"-u",2)==0){
   chunkObj=new Chunker(n);
   uploaderObj=new Uploader(n,m,userId);
   encoderObj=new Encoder(n,m,r,uploaderObj);
  //chunking
  chunkObj->chunking(buffer,buffersize,&chunklength,&left);
  blockbuffer=(unsigned char*)malloc(sizeof(unsigned char)*chunklength);
  Encoder::fileBlock_Item_t inputheader;
  memcpy(inputheader.file_header.data, argv[1], namesize);
  inputheader.file_header.filesize=size+left;
  inputheader.file_header.left=left;
  inputheader.file_header.numOfblock=n;
  inputheader.type=FILE_HEAD;
  encoderObj->addFileblock(inputheader);
  
  int total=0;
  for(int i=0;i<n;i++) {
   Encoder::fileBlock_Item_t input;
   input.block.data=blockbuffer;
  if(i<(n-1)){ 
  //encoding
  input.block.blockid=i;
  input.block.datasize=chunklength;
  input.type=BLOCKCP;  //this is not end
   memcpy(input.block.data,buffer+total,chunklength);
  total+=chunklength;
  encoderObj->addFileblock(input);
  printf("the main: it had add one block\n");
  }
   else {
	   char* leftbuffer;
	   leftbuffer=(char*)malloc(sizeof(char)*left);
	   for(int j=0;j<left;j++)
	       memcpy(leftbuffer+i,"a",1);

      input.block.blockid=i;
      input.block.datasize=chunklength;
      input.type=BLOCKCP_END;
      memcpy(input.block.data,buffer+total,chunklength-left);
      memcpy(input.block.data+chunklength-left,leftbuffer,left);
      encoderObj->addFileblock(input);
     printf("the main: it had add one block\n");
    free(leftbuffer);
   }
   //free(input.block.data);
  }
 
 // printf("fileblock.data:%s\n",input.fileblock.data);
  printf("chunklenth:%d,left:%d\n",chunklength,left);
  printf("buffersize:%d\n",buffersize);
  uploaderObj->indicateEnd();
   free(blockbuffer);
  //uploaderObj->indicateEnd();
   delete chunkObj;
  delete uploaderObj;
  delete encoderObj;

}
  
   if(strncmp(opt,"-d",2)==0) {
    //argv[3] is the user id
    decoderObj=new Decoder(n,m,r);
    downloaderObj=new Downloader(userId,decoderObj);

    FILE* fw=fopen("./decoded_copy","wb");

    decoderObj->setFilePointer(fw);
    downloaderObj->downloadFile(argv[1]);
    downloaderObj->indicateEnd();
    fclose(fw);
    delete downloaderObj;
    delete decoderObj;
  }
   free(buffer);
   fclose(fin);
   CryptoPrimitive::opensslLockCleanup();
  return 0;
}

